package com.ibl.rover.lite.common.bean;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SQLiteDatabaseHelper {

	private static final String DEFAULT_ID = "_id";

	private static final String UPDATE = "UPDATE ";
	private static final String DELETE = "DELETE FROM ";
	private static final String CREATE_TABLE = "CREATE TABLE ";
	private static final String PRIM_KEY_DEC = " (_ID integer PRIMARY KEY AUTOINCREMENT ";
	private static final String INSERT = "INSERT INTO ";
	private static final String OPEN_STMT = " (";
	private static final String CLOSE_STMT = ")";
	private static final String WHERE_ID = " WHERE _ID = ? ";
	private static final String VALUES = " VALUES";

	public static <T> AutomatedQueryStatement getAutoGeneratedStmts(
			Class<T> create) {
		T instance = null;
		StringBuilder builder = null;
		StringBuilder delete = null;
		StringBuilder insert = null;
		StringBuilder values = null;
		StringBuilder update = null;
		try {
			instance = create.newInstance();
		} catch (IllegalAccessException ex) {

		} catch (InstantiationException ex) {

		}

		if (null != instance) {
			String tableName = NameMapperHelper.toSQLName(instance.getClass()
					.getSimpleName());
			builder = new StringBuilder(CREATE_TABLE).append(tableName).append(
					PRIM_KEY_DEC);
			delete = new StringBuilder(DELETE).append(tableName).append(
					WHERE_ID);
			insert = new StringBuilder(INSERT).append(tableName).append(
					OPEN_STMT);
			update = new StringBuilder(UPDATE).append(tableName)
					.append(" SET ");

			values = new StringBuilder(VALUES + OPEN_STMT);
			List<ReflectionInfo> listReflection = new ArrayList<ReflectionInfo>();

			for (Field singleField : instance.getClass().getDeclaredFields()) {
				if (!singleField.getName().equals(DEFAULT_ID)
						&& !Modifier.isStatic(singleField.getModifiers())) {
					String sqlName = NameMapperHelper.toSQLName(singleField
							.getName());
					Class<?> dataType = singleField.getType();
					int order = singleField.getAnnotation(ColumnOrder.class)
							.Order();
					String sqlType = getSQLiteTypeString(dataType);
					listReflection.add(new ReflectionInfo(sqlName, sqlType,
							order));
				}
			}

			Collections.sort(listReflection, new Comparator<ReflectionInfo>() {
				@Override
				public int compare(ReflectionInfo object1,
						ReflectionInfo object2) {
					if (object1.getOrder() > object2.getOrder())
						return 1;
					else if (object1.getOrder() < object2.getOrder())
						return -1;
					else
						return 0;
				}
			});

			for (ReflectionInfo singleReflection : listReflection) {
				builder.append(",").append(singleReflection.getColumnName())
						.append(" ").append(singleReflection.getColumnType());

				insert.append(singleReflection.getColumnName()).append(",");
				update.append(singleReflection.getColumnName()).append("=?,");
				values.append("?,");
			}

			update.deleteCharAt(update.length() - 1);
			insert.deleteCharAt(insert.length() - 1);
			values.deleteCharAt(values.length() - 1);

			update.append(" WHERE _ID=?");
			insert.append(CLOSE_STMT);
			values.append(CLOSE_STMT);
			builder.append(CLOSE_STMT);
			insert.append(values);
			return new AutomatedQueryStatement(builder.toString(),
					insert.toString(), update.toString(), delete.toString(),
					tableName);
		}
		return null;
	}

	// TODO: remove hard coded strings and manage data type properly
	private static String getSQLiteTypeString(Class<?> c) {
		String name = c.getName();
		if (name.equals("java.util.Date"))
			return "int";
		if (name.equals("java.lang.String"))
			return "text";
		if (name.equals("short"))
			return "int";
		if (name.equals("int"))
			return "int";
		if (name.equals("long"))
			return "int";
		if (name.equals("long"))
			return "int";
		if (name.equals("java.sql.Timestamp"))
			return "int";
		if (name.equals("double"))
			return "real";
		if (name.equals("float"))
			return "real";
		if (name.equals("[B"))
			return "blob";
		if (name.equals("boolean"))
			return "bool";
		throw new IllegalArgumentException(
				"Class cannot be stored in Sqlite3 database.");
	}

}
